﻿using System.Reflection;
using System.Text;
using System.Text.Json;
using rpc_service.cache;

namespace rpc_service.core.support.assembly.roslyn.handle;

public class RoslynParamHandle
{
    private RoslynTypeHandle _roslynTypeHandle = new RoslynTypeHandle();
    
    public StringBuilder GenerateParam(MethodInfo targetMethod)
    {
        StringBuilder paramStringBuilder = new StringBuilder();

        if (targetMethod.GetParameters().Length <= 0)
        {
            return paramStringBuilder;
        }

        foreach (var parameter in targetMethod.GetParameters())
        {
            paramStringBuilder.Append($@"{_roslynTypeHandle.Handle(parameter.ParameterType)} {parameter.Name},");
        }
        
        paramStringBuilder.Remove(paramStringBuilder.Length - 1, 1);

        return paramStringBuilder;
    }

    public StringBuilder GenerateReturnType(MethodInfo targetMethod)
    {
        return new StringBuilder(_roslynTypeHandle.Handle(targetMethod.ReturnType));
    }

    public StringBuilder GenerateReturn(MethodInfo targetMethod)
    {
        StringBuilder stringBuilder = new StringBuilder();
        Type returnType = targetMethod.ReturnType;
        
        // 处理 Task<T> 类型
        if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == "Task<>".GetTypeByStr())
        {
            returnType = returnType.GetGenericArguments()[0];
        }
        
        // 处理 void 或 Task 返回类型
        if (returnType == "void".GetTypeByStr() || returnType == "Task".GetTypeByStr())
        {
            stringBuilder.AppendLine("return;");
            return stringBuilder;
        }
        
        // 处理基础类型
        if (_roslynTypeHandle.IsBasicType(returnType))
        {
            stringBuilder.AppendLine($"return responseBody;");
            return stringBuilder;
        }
        
        // 处理复杂类型 - 使用 JSON 转换
        stringBuilder.AppendLine($"return System.Text.Json.JsonSerializer.Deserialize<{_roslynTypeHandle.Handle(returnType)}>(responseBody);");
        return stringBuilder;
    }

    public void GenerateUrlParams(StringBuilder builder, MethodInfo targetMethod)
    {
        GenerateUrlParam(builder, targetMethod);
        GenerateJsonSerialization(builder, targetMethod);
    }
    
    public void GenerateUrlParam(StringBuilder builder, MethodInfo targetMethod)
    {
        ParameterInfo[] parameterTypes = targetMethod.GetParameters().ToArray();
        
        Type stringBuilderType = "StringBuilder".GetTypeByStr();
        builder.AppendLine($@"{stringBuilderType} urlBuilder = new {stringBuilderType}();");
        builder.AppendLine($@"urlBuilder.Append(url + ""?"");");
        
        foreach (var parameter in parameterTypes)
        {
            if (parameter.GetCustomAttribute<RPCParam>() == null)
            {
                continue;
            }
            
            builder.AppendLine($"urlBuilder.Append($\"{parameter.Name}={{{parameter.Name}}}&\");");
        }
        
        builder.AppendLine($"urlBuilder.Remove(urlBuilder.Length - 1, 1);");
    }

    public void GenerateJsonSerialization(StringBuilder builder, MethodInfo targetMethod)
    {
        int rpcBodyCount = targetMethod.GetParameters().Count(p => p.GetCustomAttribute<RPCBody>() != null);

        Type stringContentType = "StringContent".GetTypeByStr();
        Type encodingType = "Encoding".GetTypeByStr();
        
        Type jsonSerializerType = "JsonSerializer".GetTypeByStr();
        Type stringType = "string".GetTypeByStr();
        
        if (rpcBodyCount <= 0)
        {
            builder.AppendLine($@"{stringType} json = {jsonSerializerType}.Serialize("""");");
            builder.AppendLine($@"{stringContentType} content = new {stringContentType}("""", {encodingType}.UTF8, ""application/json"");");
            return;
        }
        
        if (rpcBodyCount > 1)
        {
            throw new Exception("Too many body parameters");
        }
        
        string parameterName = targetMethod.GetParameters().First().Name!;
        builder.AppendLine($@"{stringType} json = {jsonSerializerType}.Serialize({parameterName});");
        builder.AppendLine($@"{stringContentType} content = new {stringContentType}(json, {encodingType}.UTF8, ""application/json"");");
    }
}